package cn.dev.mybatis.proxy;

import cn.dev.mybatis.bean.SqlObject;
import cn.dev.mybatis.bean.SqlType;
import cn.dev.mybatis.cache.SqlCache;
import cn.dev.mybatis.core.SingleFactory;
import cn.dev.mybatis.exception.MybatisException;
import cn.dev.mybatis.handler.parse.SqlParseContext;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Objects;

/**
 * jdk代理类
 *
 * @since 2025-02-12
 */
public class JdkProxy implements InvocationHandler {
    private final SqlCache sqlCache = SingleFactory.get(SqlCache.class);

    private final Connection connection;

    private final boolean autoCommit;

    public JdkProxy(Connection connection, boolean autoCommit) {
        this.connection = connection;
        this.autoCommit = autoCommit;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        if (sqlCache.containsKey(proxy.getClass(), method)) {
            return sqlCache.get(proxy.getClass(), method);
        }
        try {
            connection.setAutoCommit(autoCommit);
            SqlParseContext parseContext = new SqlParseContext();
            parseContext.setSqlParser(method);
            SqlObject sqlObject = parseContext.parse(method, args);
            Object result = sqlObject.getExecutor().execute(connection);
            if (Objects.equals(SqlType.SELECT, sqlObject.getSqlType())) {
                sqlCache.put(proxy.getClass(), method, result);
            } else {
                if (connection.getAutoCommit()) {
                    sqlCache.remove(proxy.getClass());
                }
            }
            return result;
        } catch (SQLException e) {
            throw new MybatisException(e);
        }
    }
}
